/******************************************************************************************************
 *  The skeletion b+tree table database for Tokyo Cabinet
 *  the b+tree table can support the field index(json format value) like tct(table engine).
 *  specifiction:
 *    MUST BE an B+ TREE Table ENGINE 
 *    the key and value MUST BE utf-8 format.
 *    addint, adddouble, putcat,putproc,putdup, putdupback is never indexed
 *    outlist use the tcbdbout instead of tcbdbout3!
 *    the setindex command is same as the tct, Note the setindex do not add the original data to the index unless u re-index it.
 *      remove the index, u can use the TDBITVOID(9999) option.
 *        tcrmgr misc localhost setindex key 9999
 *      ReIndex, u can use the TDBITREINDEX(10000) option.
 *        tcrmgr misc localhost setindex key 10000
 *    the query command is same as the tct[todo]
 *    tcadbcopy command is not re-indexed.[todo]
 *    Key Specifiction:
 *      the key length should be less 2047(MAXKEYLEN) chars.
 *      the duplication(same) key is not allowed.
 *      the start with "_" is NOT ALLOWED, we keep reserve as internal used.
 *      the "/", "|", "\", """, "." is not allowed too. u need escape these chars.
 *      _DB/index/_conf/[FieldName]: 
 *         [IndexOptions]: the index options same as the tct's index options.[todo]
 *      _DB/index/[FieldName]/[FieldValue]/[KeyName]: the index put here, store value is the field of the key.
 *         the FieldValue will be quoted("") if it is a string.
 *         value: [KeyName]
 *    Structured-Value for Index Specifiction:
 *      STRICT JSON Object only 
 *      The first char MUST BE "{" and the last char MUST BE "}" 
 *      NO MORE BLANK CHARS BE ALLOWED
 *      the string MUST BE in double quote : ""
 *      all the key in the json object must be a string.
 *      only string, number, bool, null can be indexed.
 *      the "/", "|", "\", "_", """, "." char keep reserved. so the field value string MUST NOT USE these characters(u should escape these chars). 
 *   Structured-Value Store Specifiction:
 *      Spec.1:
 *        Store As Json String
 *        Key: [KeyName]
 *        Value: "{"[FieldName]":[FieldValue], ...}" : the json string
 *
 #test :
 tcrmgr vanish localhost 
 tcrmgr misc localhost setindex key 0 
 tcrmgr misc localhost setindex goodkey 0 
 tcrmgr misc localhost setindex key1 0 
 tcrmgr misc localhost setindex key2 0
 tcrmgr list localhost 
 tcrmgr put localhost mykey "{\"key\":\"hello\",\"goodkey\":false}"
 tcrmgr put localhost mykey2 "{\"key\":\"你好\",\"goodkey\":true}"
 tcrmgr list localhost 
 _DB/index/_conf/goodkey
 _DB/index/_conf/key
 _DB/index/_conf/key1
 _DB/index/_conf/key2
 _DB/index/goodkey/false/mykey
 _DB/index/goodkey/true/mykey2
 _DB/index/key/"hello"
 _DB/index/key/"你好"
 mykey
 mykey2
 tcrmgr misc localhost put mykey3 "{\"key\":\"hi,every body\",\"goodkey\":null, \"opt\":0, \"key2\":"same thing"}"
 
 //remove the key index
 tcrmgr misc localhost setindex key 9999
 *
 *    
 *                                          Copyright (C) 2009-2010 Riceball LEE(riceball.lee@gmail.com)
 ******************************************************************************************************/


#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <uuid/uuid.h>
#include <jansson.h>  //json 
//#include "tcjson.h"

#include "tcutil.h"
#include "tchdb.h"
#include "tcbdb.h"
#include "tcadb.h"
#include "tctdb.h"
#include "tcskelbdb.h"
#include "myconf.h"

#define TCNUMBUFSIZ    32                // size of a buffer for a number
#if defined(DEBUG)
#define MAXLISTSIZE    2                 //-1 means get all items at once.
#else
#define MAXLISTSIZE    4096*16           //-1 means get all items at once.
#endif
//#define DEBUG

#define URN_TEMPLATE "urn:uid:"

#define BDBLOCKMETHOD(TC_bdb, TC_wr)                            \
((TC_bdb)->mmtx ? tcbdblockmethod((TC_bdb), (TC_wr)) : true)
#define BDBUNLOCKMETHOD(TC_bdb)                         \
((TC_bdb)->mmtx ? tcbdbunlockmethod(TC_bdb) : true)
#define BDBLOCKCACHE(TC_bdb)                            \
((TC_bdb)->mmtx ? tcbdblockcache(TC_bdb) : true)
#define BDBUNLOCKCACHE(TC_bdb)                          \
((TC_bdb)->mmtx ? tcbdbunlockcache(TC_bdb) : true)
#define BDBTHREADYIELD(TC_bdb)                          \
do { if((TC_bdb)->mmtx) sched_yield(); } while(false)

#if defined __GNUC__
#define DisableWarning #pragma GCC system_header
#define EnableWarning  
#elif defined __SUNPRO_CC
#define DisableWarning #pragma disable_warn
#define EnableWarning  #pragma enable_warn
#elif defined _MSC_VER
#define DisableWarning #pragma warning(push, 1)
#define EnableWarning #pragma warning(pop) 
#endif

/* private function prototypes */
static bool tcbdblockmethod(TCBDB *bdb, bool wr);
static bool tcbdbunlockmethod(TCBDB *bdb);
static bool tcbdblockcache(TCBDB *bdb);
static bool tcbdbunlockcache(TCBDB *bdb);

//------------------the interface of a DB
static void* tcDBNew(void);
static void  tcDBFree(void *aDB);
static bool tcDBOpen(TCADB *adb, const char *name);
static bool tcDBClose(void *aDB);
//add/update a record(key/calue)
static bool tcDBReplace(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
//add a record. return false if key exists or other error.
static bool tcDBInsert(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
//append the value to an exists record.
static bool tcDBUpdateCat(void *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz);
static bool tcDBDelete(TCADB *aDB, const char *kbuf, int ksiz);
static void *tcDBGet(void *aDB, const char *aKey, int aKeySize, int *aValueSize);
/* Get the size of the value of a record.
 If successful, the return value is the size of the value of the corresponding record, else,
 it is -1. */
static int tcDBGetValueSize(void *aDB, const char *aKey, int aKeySize);
/* Initialize the iterator of a reocrd.
 If successful, the return value is true, else, it is false.
 The iterator is used in order to access the key of every record stored in a database. */
static bool tcDBIterInit(void *aDB);
/* Get the next key of the iterator of a database object.
 `aDB' specifies the database object.
 `aSize' specifies the pointer to the variable into which the size of the region of the return
 value is assigned.
 If successful, the return value is the pointer to the region of the next key, else, it is
 `NULL'.  `NULL' is returned when no record is to be get out of the iterator.
 Because an additional zero code is appended at the end of the region of the return value, the
 return value can be treated as a character string.  Because the region of the return value is
 allocated with the `malloc' call, it should be released with the `free' call when it is no
 longer in use. */
static void *tcDBIterNext(void *aDB, int *aSize);
/* Get forward matched keys in a database object: the first part string is matched with the aKey.
 `aDB' specifies the database object.
 `aKey' specifies the pointer to the region of the prefix.
 `aKeySize' specifies the size of the region of the prefix.
 `aMaxCount' specifies the maximum number of keys to be fetched.  If it is negative, no limit is
 specified.
 The return value is a list object of the corresponding keys.  This function does never fail.
 It returns an empty list even if no key corresponds.
 Because the object of the return value is created with the function `tclistnew', it should be
 deleted with the function `tclistdel' when it is no longer in use.  Note that this function
 may be very slow because every key in the database is scanned. */
static TCLIST *tcDBGetMatchedKeys(void *aDB, const char *aKey, int aKeySize, int aMaxCount);
/* Add an integer to a record in a database object.
 `aDB' specifies the abstract database object.
 `aKey' specifies the pointer to the region of the key.
 `aKeySize' specifies the size of the region of the key.
 `aNumber' specifies the additional value.
 If successful, the return value is the summation value, else, it is `INT_MIN'.
 If the corresponding record exists, the value is treated as an integer and is added to.  If no
 record corresponds, a new record of the additional value is stored. */
static int tcDBAddInt(void *aDB, const char *aKey, int aKeySize, int aNumber);
static double tcDBAddDouble(void *aDB, const char *aKey, int aKeySize, double aNumber);
static bool tcDBSync(void *aDB);
static bool tcDBOptimize(void *aDB, const char *aParams);
static bool tcDBClear(void *aDB);
static bool tcDBCopy(void *aDB, const char *aPath);
static bool tcDBTransBegin(void *aDB);
static bool tcDBTransCommit(void *aDB);
static bool tcDBTransAbort(void *aDB);
static const char *tcDBPath(void *aDB);
//get the record number of the db //exclude the index number and index config.
static uint64_t tcDBGetRecordNum(void *aDB);
static uint64_t tcDBSize(void *aDB);
//execute the additional command in misc.
static TCLIST *tcDBExecCmd(TCADB *aDB, const char *name, const TCLIST *args);
static bool tcDBReplaceProc(void *aDB, const void *aKey, int aKeySize, const void *aValue, int aValueSize,
                            TCPDPROC aProc, void *aProcParams);
static bool tcDBForEach(void *aDB, TCITER aIterProc, void *aIterParams);
//------------------the interface of a DB---END-----

/* callback Put/PutKeep */
typedef bool (*TCADBPUTPROC)(TCADB *aDB, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
typedef bool (*TCBDBPUTPROC)(TCBDB *aDB, const void *kbuf, int ksiz, const void *vbuf, int vsiz);
typedef bool (*TCBDBOUTPROC)(TCBDB *aDB, const void *kbuf, int ksiz);

/* add/update Key/Structured-Value with index supports */
static bool tcADBReplace(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz, const TCADBPUTPROC aPutProc);
/* remove the Key with index supports */
static bool tcADBDelete(TCADB *aDB, const char *kbuf, int ksiz);
/* set an index to a field */
static bool tcBDBIndexSet(TCBDB *aDB, const char *aFieldbuf, int aFieldSiz, const char *aOptions, int aOptionsSiz, int aOptionInt);
/* remove an index of a field */
static bool tcBDBIndexRemove(TCBDB *aDB, const char *aFieldbuf, int aFieldSiz);
//static bool tcBDBIndexClear(TCBDB *aDB, const char *kbuf, int ksiz);

/* add/update Key/Structured-Value with index supports */
static bool tcBDBReplace(TCBDB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz, const TCBDBPUTPROC aPutProc);
/* remove the Key with index supports */
static bool tcBDBDelete(TCBDB *aDB, const char *kbuf, int ksiz, const TCBDBOUTPROC aOutProc);

/*************************************************************************************************
 * API
 *************************************************************************************************/
/* u should free the result by youself. */
static inline char *GenerateUID(void) {
  uuid_t uu;
  char *char_uu; //[sizeof(URN_TEMPLATE) + 37];
  char_uu = tcmalloc(37);
  
  //strcpy (char_uu, URN_TEMPLATE);
  
  uuid_generate (uu);
  //uuid_unparse (uu, char_uu + sizeof (URN_TEMPLATE) - 1);
  uuid_unparse (uu, char_uu);
#if defined(DEBUG)
  fprintf (stderr, "uid:%s\n", char_uu);
#endif
  uuid_clear (uu);
  
  return (char_uu);  
}

static inline bool isKeepReservedChar(const char *aStr) {
  return (*aStr == '_' || *aStr == '/' || *aStr == '.' || *aStr == '|' || *aStr == '\\' || *aStr == '"');
}

//str cat json value(string, number, bool, null)
static inline void StrCatJson(char* aStr, const void* aJsonValue) {
  char numbuf[TCNUMBUFSIZ];
  switch (json_typeof((json_t*)aJsonValue)) {
    case JSON_STRING:
      strcat(aStr, "\"");
      strcat(aStr, json_string_value((json_t*)aJsonValue));
      strcat(aStr, "\"");
      break;
    case JSON_INTEGER:
      sprintf(numbuf, "%d", json_integer_value((json_t*)aJsonValue));
      strcat(aStr, numbuf);
      break;
    case JSON_REAL:
      sprintf(numbuf, "%f", json_real_value((json_t*)aJsonValue));
      strcat(aStr, numbuf);
    case JSON_TRUE:
      strcat(aStr, "true");
      break;
    case JSON_FALSE:
      strcat(aStr, "false");
      break;
    case JSON_NULL:
      strcat(aStr, "null");
      break;
    default:
      break;
  }
  
}

static void tcBDBSkelSet(ADBSKEL *skel){
#if defined(DEBUG)
  //fprintf(stderr, "%s\n", "tcBDBSkelSet");
#endif
  skel->opq = tcDBNew();
  skel->del = (void (*)(void *))tcDBFree;
  skel->open = (bool (*)(void *, const char *))tcDBOpen;
  skel->close = (bool (*)(void *))tcDBClose;
  skel->put = (bool (*)(void *, const void *, int, const void *, int))tcDBReplace;
  skel->putkeep = (bool (*)(void *, const void *, int, const void *, int))tcDBInsert;
  skel->putcat = (bool (*)(void *, const void *, int, const void *, int))tcDBUpdateCat;
  skel->out = (bool (*)(void *, const void *, int))tcDBDelete;
  skel->get = (void *(*)(void *, const void *, int, int *))tcDBGet;
  skel->vsiz = (int (*)(void *, const void *, int))tcDBGetValueSize;
  skel->iterinit = (bool (*)(void *))tcDBIterInit;
  skel->iternext = (void *(*)(void *, int *))tcDBIterNext;
  skel->fwmkeys = (TCLIST *(*)(void *, const void *, int, int))tcDBGetMatchedKeys;
  skel->addint = (int (*)(void *, const void *, int, int))tcDBAddInt;
  skel->adddouble = (double (*)(void *, const void *, int, double))tcDBAddDouble;
  skel->sync = (bool (*)(void *))tcDBSync;
  skel->optimize = (bool (*)(void *, const char *))tcDBOptimize;
  skel->vanish = (bool (*)(void *))tcDBClear;
  skel->copy = (bool (*)(void *, const char *))tcDBCopy;
  skel->tranbegin = (bool (*)(void *))tcDBTransBegin;
  skel->trancommit = (bool (*)(void *))tcDBTransCommit;
  skel->tranabort = (bool (*)(void *))tcDBTransAbort;
  skel->path = (const char *(*)(void *))tcDBPath;
  skel->rnum = (uint64_t (*)(void *))tcDBGetRecordNum;
  skel->size = (uint64_t (*)(void *))tcDBSize;
  skel->misc = (TCLIST *(*)(void *, const char *, const TCLIST *))tcDBExecCmd;
  skel->putproc =
  (bool (*)(void *, const void *, int, const void *, int, TCPDPROC, void *))tcDBReplaceProc;
  skel->foreach = (bool (*)(void *, TCITER, void *))tcDBForEach;
  
}
/* Set the b+tree database skeleton to an abstract database object. */
bool tcADBSetSkelBDB(TCADB *adb){
#if defined(DEBUG)
  //fprintf(stderr, "%s\n", "tcADBSetSkelBDB");
#endif
  assert(adb);
  if(adb->omode != ADBOVOID) return false;
  ADBSKEL skel;
  memset(&skel, 0, sizeof(skel));
  tcBDBSkelSet(&skel);
  if(!tcadbsetskel(adb, &skel)){
    tcadbdel(skel.opq);
    return false;
  }
  return true;
}

bool initialize(ADBSKEL *skel){
  tcBDBSkelSet(skel);
  return true;
}


void tcSkelBDBSetEcode(TCBDB *bdb, int aErrCode, const char *aMsg, const char *filename, int line, const char *func){
  assert(bdb && filename && line >= 1 && func);
  char *s = tcsprintf("%s:%s",func, aMsg);
  tchdbsetecode(bdb->hdb, aErrCode, filename, line, s);
  free(s);
}
//*/

//const char *tcSkelBDBErrMsg(int ecode){
//  switch (ecode) {
//    case TCEREMOVEINDEX: return "remove an index failed.";
//    default: return tcbdberrmsg(ecode);
//  }
//}

/*************************************************************************************************
 * private features
 *************************************************************************************************/
static void* tcDBNew(void){
  return tcadbnew();
}

static void tcDBFree(void *aDB){
  tcadbdel((TCADB*) aDB);
}

static bool tcDBClose(void *aDB) {
  return tcadbclose((TCADB*) aDB);
}

static bool tcDBUpdateCat(void *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz){
  return tcadbputcat((TCADB*) aDB, kbuf, ksiz, vbuf, vsiz);
}

static void *tcDBGet(void *aDB, const char *aKey, int aKeySize, int *aValueSize){
  return tcadbget((TCADB*) aDB, aKey, aKeySize, aValueSize);
}

static int tcDBGetValueSize(void *aDB, const char *aKey, int aKeySize){
  return tcadbvsiz((TCADB*) aDB, aKey, aKeySize);
}

static bool tcDBIterInit(void *aDB) {
  return tcadbiterinit((TCADB*) aDB);
}

static void* tcDBIterNext(void *aDB, int *aSize){
  return tcadbiternext((TCADB*) aDB, aSize);
}

static TCLIST *tcDBGetMatchedKeys(void *aDB, const char *aKey, int aKeySize, int aMaxCount) {
  return tcadbfwmkeys((TCADB*) aDB, aKey, aKeySize, aMaxCount);
}

static int tcDBAddInt(void *aDB, const char *aKey, int aKeySize, int aNumber){
  return tcadbaddint((TCADB*) aDB, aKey, aKeySize, aNumber);
}

static double tcDBAddDouble(void *aDB, const char *aKey, int aKeySize, double aNumber){
  return tcadbadddouble((TCADB*) aDB, aKey, aKeySize, aNumber);
}

static bool tcDBOptimize(void *aDB, const char *aParams){
  return tcadboptimize((TCADB*) aDB, aParams);
}

static bool tcDBClear(void *aDB){
  return tcadbvanish((TCADB*) aDB);
}

//TODO: Copy From maybe need RE-INDEX
static bool tcDBCopy(void *aDB, const char *aPath){
  return tcadbcopy((TCADB*) aDB, aPath);
}
static bool tcDBTransBegin(void *aDB){
  return tcadbtranbegin((TCADB*) aDB);
}

static bool tcDBTransCommit(void *aDB){
  return tcadbtrancommit((TCADB*) aDB);
}

static bool tcDBTransAbort(void *aDB) {
  return tcadbtranabort((TCADB*) aDB);
}

static const char *tcDBPath(void *aDB){
  return tcadbpath((TCADB*) aDB);
}

static uint64_t tcDBSize(void *aDB){
  return tcadbsize((TCADB*) aDB);
}

static bool tcDBSync(void *aDB) {
  return tcadbsync((TCADB*) aDB);
}

static bool tcDBReplaceProc(void *aDB, const void *aKey, int aKeySize, const void *aValue, int aValueSize,
                            TCPDPROC aProc, void *aProcParams){
  return tcadbputproc((TCADB*) aDB, aKey, aKeySize, aValue, aValueSize, aProc, aProcParams);
}

static bool tcDBForEach(void *aDB, TCITER aIterProc, void *aIterParams) {
  return tcadbforeach(aDB, aIterProc, aIterParams);
}

static bool tcDBOpen(TCADB *adb, const char *name){
  assert(adb && name);
  if(adb->omode != ADBOVOID) return false;
  TCLIST *elems = tcstrsplit(name, "#");
  char *path = tclistshift2(elems);
  if(!path){
    tclistdel(elems);
    return false;
  }
  int dbgfd = -1;
  int64_t bnum = -1;
  int64_t capnum = -1;
  int64_t capsiz = -1;
  bool owmode = true;
  bool ocmode = true;
  bool otmode = false;
  bool onlmode = false;
  bool onbmode = false;
  int8_t apow = -1;
  int8_t fpow = -1;
  bool tlmode = false;
  bool tdmode = false;
  bool tbmode = false;
  bool ttmode = false;
  int32_t rcnum = -1;
  int64_t xmsiz = -1;
  int32_t dfunit = -1;
  int32_t lmemb = -1;
  int32_t nmemb = -1;
  int32_t lcnum = -1;
  int32_t ncnum = -1;
  int32_t width = -1;
  int64_t limsiz = -1;
  int ln = TCLISTNUM(elems);
  for(int i = 0; i < ln; i++){
    const char *elem = TCLISTVALPTR(elems, i);
    char *pv = strchr(elem, '=');
    if(!pv) continue;
    *(pv++) = '\0';
    if(!tcstricmp(elem, "dbgfd")){
      dbgfd = tcatoi(pv);
    } else if(!tcstricmp(elem, "bnum")){
      bnum = tcatoix(pv);
    } else if(!tcstricmp(elem, "capnum")){
      capnum = tcatoix(pv);
    } else if(!tcstricmp(elem, "capsiz")){
      capsiz = tcatoix(pv);
    } else if(!tcstricmp(elem, "mode")){
      owmode = strchr(pv, 'w') || strchr(pv, 'W');
      ocmode = strchr(pv, 'c') || strchr(pv, 'C');
      otmode = strchr(pv, 't') || strchr(pv, 'T');
      onlmode = strchr(pv, 'e') || strchr(pv, 'E');
      onbmode = strchr(pv, 'f') || strchr(pv, 'F');
    } else if(!tcstricmp(elem, "apow")){
      apow = tcatoix(pv);
    } else if(!tcstricmp(elem, "fpow")){
      fpow = tcatoix(pv);
    } else if(!tcstricmp(elem, "opts")){
      if(strchr(pv, 'l') || strchr(pv, 'L')) tlmode = true;
      if(strchr(pv, 'd') || strchr(pv, 'D')) tdmode = true;
      if(strchr(pv, 'b') || strchr(pv, 'B')) tbmode = true;
      if(strchr(pv, 't') || strchr(pv, 'T')) ttmode = true;
    } else if(!tcstricmp(elem, "rcnum")){
      rcnum = tcatoix(pv);
    } else if(!tcstricmp(elem, "xmsiz")){
      xmsiz = tcatoix(pv);
    } else if(!tcstricmp(elem, "dfunit")){
      dfunit = tcatoix(pv);
    } else if(!tcstricmp(elem, "lmemb")){
      lmemb = tcatoix(pv);
    } else if(!tcstricmp(elem, "nmemb")){
      nmemb = tcatoix(pv);
    } else if(!tcstricmp(elem, "lcnum")){
      lcnum = tcatoix(pv);
    } else if(!tcstricmp(elem, "ncnum")){
      ncnum = tcatoix(pv);
    } else if(!tcstricmp(elem, "width")){
      width = tcatoix(pv);
    } else if(!tcstricmp(elem, "limsiz")){
      limsiz = tcatoix(pv);
    } 
  }
  tclistdel(elems);
  adb->omode = ADBOVOID;
  if(tcstribwm(path, ".tcb") || tcstribwm(path, ".bdb")){
    TCBDB *bdb = tcbdbnew();
    if(dbgfd >= 0) tcbdbsetdbgfd(bdb, dbgfd);
    tcbdbsetmutex(bdb);
    int opts = 0;
    if(tlmode) opts |= BDBTLARGE;
    if(tdmode) opts |= BDBTDEFLATE;
    if(tbmode) opts |= BDBTBZIP;
    if(ttmode) opts |= BDBTTCBS;
    tcbdbtune(bdb, lmemb, nmemb, bnum, apow, fpow, opts);
    tcbdbsetcache(bdb, lcnum, ncnum);
    if(xmsiz >= 0) tcbdbsetxmsiz(bdb, xmsiz);
    if(dfunit >= 0) tcbdbsetdfunit(bdb, dfunit);
    if(capnum > 0) tcbdbsetcapnum(bdb, capnum);
    int omode = owmode ? BDBOWRITER : BDBOREADER;
    if(ocmode) omode |= BDBOCREAT;
    if(otmode) omode |= BDBOTRUNC;
    if(onlmode) omode |= BDBONOLCK;
    if(onbmode) omode |= BDBOLCKNB;
    if(!tcbdbopen(bdb, path, omode)){
      tcbdbdel(bdb);
      TCFREE(path);
      return false;
    }
    adb->bdb = bdb;
    adb->cur = tcbdbcurnew(bdb);
    adb->omode = ADBOBDB;
  }
  TCFREE(path);
  if(adb->omode == ADBOVOID) return false;
  return true;
}

static inline uint64_t tcBDBRangeCount(TCBDB *adb, char *kbuf, int ksiz){
  uint64_t vResult = 0;
  TCLIST *vList = NULL;
  char vLastKeyBuf[MAXKEYLEN+1], vEndkbuf[MAXKEYLEN+1];
  int vLastKeySiz = ksiz, vEndksiz = ksiz;
  strcpy(vLastKeyBuf, kbuf);
  strcpy(vEndkbuf, kbuf);
  vEndkbuf[vEndksiz-1] = vEndkbuf[vEndksiz-1] + 1;
  int vCount;
  do {
    vList = tcbdbrange(adb, vLastKeyBuf, vLastKeySiz, false, vEndkbuf, vEndksiz, false, MAXLISTSIZE);
    if (vList) vCount = TCLISTNUM(vList); else vCount = 0;
    if (vCount > 0) {
      vResult = vResult + vCount;
      TCLISTVAL(kbuf, vList, vCount - 1, ksiz);
      vLastKeySiz = ksiz;
      strcpy(vLastKeyBuf, kbuf);
    }
    if (vList) tclistdel(vList);
  } while (vCount > 0);
  return vResult;
}

static inline uint64_t tcBDBIndexNum(TCBDB *adb){
  return tcBDBRangeCount(adb, IDXKEY, strlen(IDXKEY)) - tcBDBRangeCount(adb, IDXCONFIGKEY, strlen(IDXCONFIGKEY));
}

static inline uint64_t tcBDBIndexConfigNum(TCBDB *adb){
  return tcBDBRangeCount(adb, IDXCONFIGKEY, strlen(IDXCONFIGKEY));
}

static uint64_t tcDBGetRecordNum(void *aDB){
  //uint64_t vResult = tcbdbrnum(adb->bdb) - tcBDBRangeCount(adb->bdb, IDXKEY, strlen(IDXKEY));
  //fprintf(stderr, "rnum:%d\n", vResult);
  uint64_t vResult = tcbdbrnum(((TCADB*)aDB)->bdb);
  return vResult;
}

/* JSON -----
 Return the Parsed string if success. and the aValue will be skiped the position of the string.
 u need free the string to dispose the resource.
 NOte: CHAR MUST use the '', string/array use the "" in C.
 */
/*
 static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
 static const char *parse_string(const char **aValue){
 const char vSep = **aValue;
 const char *ptr=*aValue+1;char *ptr2;char *out;int len=0;unsigned uc;
 //aStrLen = 0;
 if (vSep != '\'' && vSep != '"') return 0; //not a string.
 
 while (*ptr!=vSep && (unsigned char)*ptr>31 && ++len) if (*ptr++ == '\\') ptr++;	// Skip escaped quotes.
 
 //fprintf(stderr,"l:%d\n",len);
 //aValue = skip(aValue+1);
 //fprintf(stderr,"sl:%d\n",len);
 out = (char*)malloc(len+1);	// This is how long we need for the string, roughly.
 //fprintf(stderr,"l:%d\n",len);
 if (!out) return 0;
 
 ptr=*aValue + 1;ptr2=out;
 while ( *ptr!=vSep && (unsigned char)*ptr>31)
 {
 if (*ptr!='\\') *ptr2++=*ptr++;
 else
 {
 ptr++;
 switch (*ptr)
 {
 case 'b': *ptr2++='\b';	break;
 case 'f': *ptr2++='\f';	break;
 case 'n': *ptr2++='\n';	break;
 case 'r': *ptr2++='\r';	break;
 case 't': *ptr2++='\t';	break;
 case 'u':	 // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
 sscanf(ptr+1,"%4x",&uc);	// get the unicode char.
 len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
 
 switch (len) {
 case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
 case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
 case 1: *--ptr2 =(uc | firstByteMark[len]);
 }
 ptr2+=len;ptr+=4;
 break;
 default:  *ptr2++=*ptr; break;
 }
 ptr++;
 }
 }
 *ptr2=0;
 if (*ptr==vSep) ptr++;
 *aValue = ptr;
 return out;
 }
 //*/
static bool tcBDBIndexRemove(TCBDB *aDB, const char *aFieldbuf, int aFieldSiz) {
#if defined(ENABLE_TRANSACTION)  
  bool vResult = tcbdbtranbegin(aDB); //TODO: this(transaction) will be a problem in the future.
#else
  bool vResult = true;
#endif
#if defined(DEBUG)
  //fprintf(stderr, "begin remove index %s .\n", aFieldbuf);
#endif
  
#if defined(ENABLE_TRANSACTION)  
  if (vResult) {
#endif
    char vIdxName[MAXKEYLEN+1];
    strcpy(vIdxName, IDXKEY);
    strncat(vIdxName, aFieldbuf, aFieldSiz);
    strcat(vIdxName, "/");
    //vResult = tcbdbout3(aDB, vIdxName, strlen(vIdxName));
    TCLIST *vList = tcbdbfwmkeys2(aDB, vIdxName, MAXLISTSIZE);
    int vCount = 0;
    if (vList) vCount = tclistnum(vList);
    while (vCount > 0 && vResult) {
      //vCount--;
      for (int i= 0; i < vCount; i++) {
        const char *kbuf;
        int ksiz;
        TCLISTVAL(kbuf, vList, i, ksiz);
        vResult = tcbdbout3(aDB, kbuf, ksiz);
        if (!vResult) {
#if defined(DEBUG)
          fprintf(stderr, "remove the index %s failed: %s.\n", kbuf, tcbdberrmsg(tcbdbecode(aDB)));
#endif
          tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
          break;
        }
      }
      if (vResult) {
        tclistdel(vList);
        vList = tcbdbfwmkeys2(aDB, vIdxName, MAXLISTSIZE);
        if (vList) vCount = tclistnum(vList); else vCount = 0;
      }
    } 
    if (vList) tclistdel(vList);
    if (vResult) {
      strcpy(vIdxName, IDXCONFIGKEY);
      strncat(vIdxName, aFieldbuf, aFieldSiz);
      vResult = tcbdbout2(aDB, vIdxName);
#if defined(ENABLE_TRANSACTION)  
      if (vResult) {
        vResult = tcbdbtrancommit(aDB);
#if defined(DEBUG)
        //        fprintf(stderr, "remove the index %s ok.\n", aFieldbuf);
#endif
      }
      else {
        tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
        tcbdbtranabort(aDB);
#if defined(DEBUG)
        fprintf(stderr, "remove Index Config %s failed.\n", vIdxName);
#endif
      }
#endif
    }
    else {
#if defined(DEBUG)
      fprintf(stderr, "remove Index %s failed: %s.\n", vIdxName, tcbdberrmsg(tcbdbecode(aDB)));
#endif
      tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
      tcbdbtranabort(aDB);
#endif
    }
    
#if defined(ENABLE_TRANSACTION)  
  }
  else {
#if defined(DEBUG)
    fprintf(stderr, "remove Index %s can not begin transaction failed.\n", aFieldbuf);
#endif
    tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
  }
#endif
  return vResult;
}

static bool tcBDBReIndex(TCBDB *aDB, const char *aFieldbuf, int aFieldSiz, const char *aOptions, int aOptionsSiz, int aOptionInt){
#if defined(ENABLE_TRANSACTION)  
  bool vResult = tcbdbtranbegin(aDB); //TODO: this(transaction) will be a performance problem in the future.
#else
  bool vResult = true;
#endif
  
#if defined(ENABLE_TRANSACTION)  
  if (vResult) {
#endif
    char vIdxName[MAXKEYLEN+1];
    //    strcpy(vIdxName, IDXKEY);
    //    strncat(vIdxName, aFieldbuf, aFieldSiz);
    //    strcat(vIdxName, "/");
    TCLIST *vList = tcbdbrange(aDB, NULL, 0, true, NULL, 0, true, MAXLISTSIZE);
    int vCount = 0;
    if (vList) vCount = tclistnum(vList);
    while (vCount > 0 && vResult) {
      json_t *vRoot;
      json_error_t vError;
      
      const char *kbuf, *vbuf;
      int ksiz, vsiz;
      for (int i= 0; i < vCount; i++) {//through out the fields:
        TCLISTVAL(kbuf, vList, i, ksiz);
#if defined(DEBUG)
        //        fprintf(stderr, "reindex the index begin %s i:%d.\n", kbuf, i);
#endif
        if (isKeepReservedChar(kbuf)) {
          continue;
        }
#if defined(DEBUG)
        //        fprintf(stderr, "reindex the index %s i:%d.\n", kbuf, i);
#endif
        vbuf = tcbdbget2(aDB, kbuf);
        vsiz = strlen(vbuf);
        
        //Now Parse the value and index it.        
        vRoot = json_loads(vbuf, &vError); //if (json_is_object(vRoot))
        if (vRoot) {
          const char *vFieldKey;
          json_t *vFieldValue;
          //char vIdxName[MAXKEYLEN+1];
          //          int vIsIndex;
          void *iter = json_object_iter(vRoot);
          while(iter)
          {
            vFieldKey = json_object_iter_key(iter);
            if (strcmp(vFieldKey, aFieldbuf) == 0) {
              vFieldValue = json_object_iter_value(iter);
#if defined(DEBUG)
              //              fprintf(stderr, "Find index field(%s) \n", vFieldKey);
#endif
              
              //vIdxName = tcsprintf("%s%s", IDXCONFIGKEY, key);
              if ((strlen(IDXCONFIGKEY)+strlen(vFieldKey) > MAXKEYLEN)) {
                vResult = false;
                tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
                tcbdbtranabort(aDB);
#endif
#if defined(DEBUG)
                fprintf(stderr, "Put field too long(%s) \n", vFieldKey);
#endif
                break;
              }
              if (json_is_object(vFieldValue) || json_is_array(vFieldValue)) {
                continue;
              }
              //            strcpy(vIdxName, IDXCONFIGKEY);
              //            strcat(vIdxName, vFieldKey);
              //            vIsIndex = tcbdbvsiz2(aDB, vIdxName);
              //TCFREE(vIdxName);
              //            if (vIsIndex >= 0) { //it is the index field, need to store the index.
              strcpy(vIdxName, IDXKEY);
              strcat(vIdxName, vFieldKey);
              strcat(vIdxName, "/");
              StrCatJson(vIdxName, vFieldValue);
              
              strcat(vIdxName, "/");
              strncat(vIdxName, kbuf, ksiz);
              vResult = tcbdbput(aDB, vIdxName, strlen(vIdxName), kbuf, ksiz);//*[bug] The duplication index(FieldValue) not supported. TC can not support the putdup in tranbegin...trancommit
              if (!vResult) {
                tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
                tcbdbtranabort(aDB);
#endif
#if defined(DEBUG)
                fprintf(stderr, "can not save the index(%s)\n", vIdxName);
#endif
                break;
              }
              //            } //if (vIsIndex >= 0)
            }
            
            iter = json_object_iter_next(vRoot, iter);
          }
          json_decref(vRoot);    
        }
        
#if defined(DEBUG)
        //        fprintf(stderr, "reindex the index %s end.\n", kbuf);
#endif
      } //for structure-value through out field
      if (vResult) {
        TCLIST *t = vList;
        vList = tcbdbrange(aDB, kbuf, ksiz, false, NULL, 0, true, MAXLISTSIZE);
        tclistdel(t);
        if (vList) {
          vCount = tclistnum(vList);
#if defined(DEBUG)
          //          fprintf(stderr, "Find the count %d.\n", vCount);
#endif
        }
        else vCount = 0;
      }
      else {
        break;
      }
      
    } //while 
    if (vList) tclistdel(vList);
#if defined(ENABLE_TRANSACTION)  
    if (vResult) {
      vResult = tcbdbtrancommit(aDB);
    }
    else {
      tcbdbtranabort(aDB);
#if defined(DEBUG)
      fprintf(stderr, "reIndex %s failed: %s.\n", aFieldbuf, tcbdberrmsg(tcbdbecode(aDB)));
#endif
      tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
    }
    
  }
#endif
#if defined(ENABLE_TRANSACTION)  
  else {
#if defined(DEBUG)
    fprintf(stderr, "reIndex %s can not begin transaction failed.\n", aFieldbuf);
#endif
    tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
  }
#endif
  
  return vResult;  
}

static bool tcBDBIndexSet(TCBDB *aDB, const char *aFieldbuf, int aFieldSiz, const char *aOptions, int aOptionsSiz, int aOptionInt){
  bool vResult;
  char vIdxName[MAXKEYLEN+1];
  strcpy(vIdxName, IDXCONFIGKEY);
  strcat(vIdxName, aFieldbuf);
  //  if (aOptionInt == -1) {
  //    aOptionInt = tctdbstrtoindextype(aOptions);
  //  }
  //  vResult = tcBDBReIndex(aDB, aFieldbuf, aFieldSiz, aOptions, aOptionsSiz, aOptionInt);
  //  if (vResult) {
  vResult = tcbdbput(aDB, vIdxName, strlen(vIdxName), aOptions, aOptionsSiz);
  //  }
  return vResult;
}

static bool tcBDBDelete(TCBDB *aDB, const char *kbuf, int ksiz, const TCBDBOUTPROC aOutProc){
  bool vResult = false;
  json_t *vRoot;
  json_error_t vError;
  
#if defined(ENABLE_TRANSACTION)  
  if (tcbdbtranbegin(aDB)) {
#endif
    int vsiz;
    char *vbuf = tcbdbget(aDB, kbuf, ksiz, &vsiz);
    if (vbuf) { //* [bug] delete a record not exists will be fatal error: Segmentation fault
      vRoot = json_loads(vbuf, &vError); //if (json_is_object(vRoot))
      if (vRoot) {
        //char numbuf[TCNUMBUFSIZ];
        const char *vFieldKey;
        json_t *vFieldValue;
        char vIdxName[MAXKEYLEN+1];
        int vIsIndex;
        void *iter = json_object_iter(vRoot);
        while(iter)
        {
          vFieldKey = json_object_iter_key(iter);
          vFieldValue = json_object_iter_value(iter);
          
          //vIdxName = tcsprintf("%s%s", IDXCONFIGKEY, key);
          if ((strlen(IDXCONFIGKEY)+strlen(vFieldKey) > MAXKEYLEN)) {
            vResult = false;
            tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
            tcbdbtranabort(aDB);
#endif
#if defined(DEBUG)
            fprintf(stderr, "the field too long(%s) \n", vFieldKey);
#endif
            break;
          }
          if (json_is_object(vFieldValue) || json_is_array(vFieldValue)) {
            continue;
          }
          strcpy(vIdxName, IDXCONFIGKEY);
          strcat(vIdxName, vFieldKey);
          vIsIndex = tcbdbvsiz2(aDB, vIdxName);
          //TCFREE(vIdxName);
          if (vIsIndex >= 0) { //it is the index field, need to store the index.
            strcpy(vIdxName, IDXKEY);
            strcat(vIdxName, vFieldKey);
            strcat(vIdxName, "/");
            StrCatJson(vIdxName, vFieldValue);
            
            strcat(vIdxName, "/");
            strncat(vIdxName, kbuf, ksiz);
            vResult = tcbdbout(aDB, vIdxName, strlen(vIdxName));
          }
          
          iter = json_object_iter_next(vRoot, iter);
        } //end-while
        json_decref(vRoot);    
      }
      else {
        vResult = true;
      }
    } //end-if(vbuf)
    vResult = aOutProc(aDB, kbuf, ksiz);  //* [Bug] can not delete a record if no index exists.
#if defined(ENABLE_TRANSACTION)  
    if (vResult) {
      vResult = tcbdbtrancommit(aDB);
    } 
    else {
      tcbdbtranabort(aDB);
    }
#endif
#if defined(ENABLE_TRANSACTION)  
  } //tcadbtran
  else {
    vResult = aOutProc(aDB, kbuf, ksiz);
  }  
#endif
  return vResult;
  
}

static bool tcADBDelete(TCADB *aDB, const char *kbuf, int ksiz){
  bool vResult = false;
  json_t *vRoot;
  json_error_t vError;
#if defined(ENABLE_TRANSACTION)  
  if (tcadbtranbegin(aDB)) {
#endif
    int vsiz;
    char *vbuf = tcadbget(aDB, kbuf, ksiz, &vsiz);
    if (vbuf) {
      vRoot = json_loads(vbuf, &vError); //if (json_is_object(vRoot))
      if (vRoot) {
        //char numbuf[TCNUMBUFSIZ];
        const char *vFieldKey;
        json_t *vFieldValue;
        char vIdxName[MAXKEYLEN+1];
        int vIsIndex;
        void *iter = json_object_iter(vRoot);
        while(iter)
        {
          vFieldKey = json_object_iter_key(iter);
          vFieldValue = json_object_iter_value(iter);
          
          //vIdxName = tcsprintf("%s%s", IDXCONFIGKEY, key);
          if ((strlen(IDXCONFIGKEY)+strlen(vFieldKey) > MAXKEYLEN)) {
            vResult = false;
            tcbdbsetecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
            tcadbtranabort(aDB);
#endif
            break;
          }
          if (json_is_object(vFieldValue) || json_is_array(vFieldValue)) {
            continue;
          }
          strcpy(vIdxName, IDXCONFIGKEY);
          strcat(vIdxName, vFieldKey);
          vIsIndex = tcadbvsiz2(aDB, vIdxName);
          //TCFREE(vIdxName);
          if (vIsIndex >= 0) { //it is the index field, need to store the index.
            strcpy(vIdxName, IDXKEY);
            strcat(vIdxName, vFieldKey);
            strcat(vIdxName, "/");
            StrCatJson(vIdxName, vFieldValue);
            
            strcat(vIdxName, "/");
            strncat(vIdxName, kbuf, ksiz);
            vResult = tcadbout(aDB, vIdxName, strlen(vIdxName));
          }
          
          iter = json_object_iter_next(vRoot, iter);
        } //end-while(iter)
        json_decref(vRoot);    
      }
      else {
        vResult = true;
      }
    } 
    
    vResult = tcadbout(aDB, kbuf, ksiz);
#if defined(ENABLE_TRANSACTION)  
    if (vResult) vResult = tcadbtrancommit(aDB); else tcadbtranabort(aDB);
#endif
#if defined(ENABLE_TRANSACTION)  
  }
  else {
    vResult = tcadbout(aDB, kbuf, ksiz);
  }  
#endif
  return vResult;
  
}

static bool tcBDBReplace(TCBDB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz, const TCBDBPUTPROC aPutProc){
  bool vResult = false;
  if (isKeepReservedChar(kbuf)) {
#if defined(DEBUG)
    fprintf(stderr, "Put error: the key is keep reserved(%s)\n", kbuf);
#endif
    tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
    return vResult;
  }
  //char *vJsonStr = skip(vbuf+1);
  
  json_t *vRoot;
  json_error_t vError;
  
  //* [bug] the ttserver pass the kbuf and vbuf no end with "\0"
  char v, *t = NULL;
  if (vbuf[vsiz] != '\0') {
    v = vbuf[vsiz];
    t = vbuf;
    t[vsiz] = '\0';
  }
  vRoot = json_loads(vbuf, &vError); //if (json_is_object(vRoot))
  if (t) t[vsiz] = v;
  if (vRoot) {
#if defined(ENABLE_TRANSACTION)  
    if (tcbdbtranbegin(aDB)) {
#endif
      //char numbuf[TCNUMBUFSIZ];
      const char *vFieldKey;
      json_t *vFieldValue;
      char vIdxName[MAXKEYLEN+1];
      int vIsIndex;
      void *iter = json_object_iter(vRoot);
      while(iter)
      {
        vFieldKey = json_object_iter_key(iter);
        vFieldValue = json_object_iter_value(iter);
        
        //vIdxName = tcsprintf("%s%s", IDXCONFIGKEY, key);
        if ((strlen(IDXCONFIGKEY)+strlen(vFieldKey) > MAXKEYLEN)) {
          vResult = false;
          tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
          tcbdbtranabort(aDB);
#endif
#if defined(DEBUG)
          fprintf(stderr, "Put field too long(%s) \n", vFieldKey);
#endif
          break;
        }
        if (json_is_object(vFieldValue) || json_is_array(vFieldValue)) {
          continue;
        }
        strcpy(vIdxName, IDXCONFIGKEY);
        strcat(vIdxName, vFieldKey);
        vIsIndex = tcbdbvsiz2(aDB, vIdxName);
        //TCFREE(vIdxName);
        if (vIsIndex >= 0) { //it is the index field, need to store the index.
          strcpy(vIdxName, IDXKEY);
          strcat(vIdxName, vFieldKey);
          strcat(vIdxName, "/");
          StrCatJson(vIdxName, vFieldValue);
          
          strcat(vIdxName, "/");
          strncat(vIdxName, kbuf, ksiz);
          vResult = tcbdbput(aDB, vIdxName, strlen(vIdxName), kbuf, ksiz);//*[bug] The duplication index(FieldValue) not supported. TC can not support the putdup in tranbegin...trancommit
          if (!vResult) {
            tcbdbsetecode(aDB, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
            tcbdbtranabort(aDB);
#endif
#if defined(DEBUG)
            fprintf(stderr, "can not save the index(%s)\n", vIdxName);
#endif
            break;
          }
        }
        else {
          vResult = true;
#if defined(DEBUG)
          fprintf(stderr, "this field %s is not indexed.\n", vFieldKey);
#endif
        }
        
        iter = json_object_iter_next(vRoot, iter);
      }
      if (vResult) vResult = aPutProc(aDB, kbuf, ksiz, vbuf, vsiz);
#if defined(ENABLE_TRANSACTION)  
      if (vResult) {
        vResult = tcbdbtrancommit(aDB); 
#if defined(DEBUG)
        if (!vResult) fprintf(stderr, "can not trancommit the key/value(%s:%s)\n", kbuf, vbuf);
#endif      
      } 
      else {
        tcbdbtranabort(aDB);      
#if defined(DEBUG)
        fprintf(stderr, "can not put the key/value(%s:%s)\n", kbuf, vbuf);
#endif
      }
    } //tcadbtran
#endif
    json_decref(vRoot);    
  }
  else {
    vResult = aPutProc(aDB, kbuf, ksiz, vbuf, vsiz);
#if defined(DEBUG)
    fprintf(stderr, "json error: on line %d: %s\n", vError.line, vError.text);
#endif
  }  
  return vResult;
  
}

static bool tcADBReplace(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz, const TCADBPUTPROC aPutProc){
  bool vResult = true;
  if (isKeepReservedChar(kbuf)) {
#if defined(DEBUG)
    fprintf(stderr, "Put error: the key is keep reserved(%s)\n", kbuf);
#endif
    
    errno = EACCES;
    tcbdbsetecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
    return false;
  }
  
  //char *vJsonStr = skip(vbuf+1);
  
  json_t *vRoot;
  json_error_t vError;
  
  //* [bug] the ttserver pass the kbuf and vbuf no end with "\0"
  char v, *t = NULL;
  if (vbuf[vsiz] != '\0') {
    v = vbuf[vsiz];
    t = vbuf;
    t[vsiz] = '\0';
  }
  vRoot = json_loads(vbuf, &vError); //if (json_is_object(vRoot))
  if (t) t[vsiz] = v;
  if (vRoot) {
#if defined(ENABLE_TRANSACTION)  
    if (tcadbtranbegin(aDB)) {
#endif
      //char numbuf[TCNUMBUFSIZ];
      const char *vFieldKey;
      json_t *vFieldValue;
      char vIdxName[MAXKEYLEN+1];
      int vIsIndex;
      void *iter = json_object_iter(vRoot);
      while(iter)
      {
        vFieldKey = json_object_iter_key(iter);
        vFieldValue = json_object_iter_value(iter);
        
        //vIdxName = tcsprintf("%s%s", IDXCONFIGKEY, key);
        if ((strlen(IDXCONFIGKEY)+strlen(vFieldKey) > MAXKEYLEN)) {
          vResult = false;
          tcbdbsetecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
          tcadbtranabort(aDB);
#endif
#if defined(DEBUG)
          fprintf(stderr, "Put field too long(%s) \n", vFieldKey);
#endif
          break;
        }
        if (json_is_object(vFieldValue) || json_is_array(vFieldValue)) {
          continue;
        }
        strcpy(vIdxName, IDXCONFIGKEY);
        strcat(vIdxName, vFieldKey);
        vIsIndex = tcadbvsiz2(aDB, vIdxName);
        //TCFREE(vIdxName);
        if (vIsIndex >= 0) { //it is the index field, need to store the index.
#if defined(DEBUG)
          //fprintf(stderr, "begin to store index(%s)\n", vFieldKey);
#endif
          strcpy(vIdxName, IDXKEY);
          strcat(vIdxName, vFieldKey);
          strcat(vIdxName, "/");
          StrCatJson(vIdxName, vFieldValue);
          
          strcat(vIdxName, "/");
          strncat(vIdxName, kbuf, ksiz);
          vResult = tcadbput(aDB, vIdxName, strlen(vIdxName), kbuf, ksiz);
          if (!vResult) {
            tcbdbsetecode(aDB->bdb, TCEINVALID, __FILE__, __LINE__, __func__);
#if defined(ENABLE_TRANSACTION)  
            tcadbtranabort(aDB);
#endif
#if defined(DEBUG)
            fprintf(stderr, "can not save the index(%s)\n", vIdxName);
#endif
            break;
          }
        }
        
        
        iter = json_object_iter_next(vRoot, iter);
      }
      if (vResult) vResult = aPutProc(aDB, kbuf, ksiz, vbuf, vsiz);
#if defined(ENABLE_TRANSACTION)  
      if (vResult) {        
        vResult = tcadbtrancommit(aDB);
#if defined(DEBUG)
        fprintf(stderr, "put %s tran :%d\n", kbuf, vResult);
#endif
        
      }
      else 
        tcadbtranabort(aDB);
    } //tcadbtran
#if defined(DEBUG)
    else {
      fprintf(stderr, "put tran failed:%s\n", kbuf);
    }
#endif
#endif
    
    json_decref(vRoot);    
  }
  else {
    vResult = aPutProc(aDB, kbuf, ksiz, vbuf, vsiz);
#if defined(DEBUG)
    fprintf(stderr, "json error: on line %d: %s\n", vError.line, vError.text);
#endif
  }
  return vResult;
}

/* Store a record into a database object.
 `aDB' specifies the database object.
 `kbuf' specifies the pointer to the region of the key.
 `ksiz' specifies the size of the region of the key.
 `vbuf' specifies the pointer to the region of the value.
 `vsiz' specifies the size of the region of the value.
 If successful, the return value is true, else, it is false. */
static bool tcDBReplace(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz){
  assert(aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  bool vResult;
  
  if (vsiz > 4 && vbuf[0] == '{' && vbuf[vsiz-1] == '}') {
    vResult = tcADBReplace(aDB, (void *)kbuf, ksiz, (void *)vbuf, vsiz, tcadbput);
  }
  else {
    vResult = tcadbput(aDB, kbuf, ksiz, vbuf, vsiz);
  }
  return vResult;
}


/* Store a new record into a database object.
 `aDB' specifies the database object.
 `kbuf' specifies the pointer to the region of the key.
 `ksiz' specifies the size of the region of the key.
 `vbuf' specifies the pointer to the region of the value.
 `vsiz' specifies the size of the region of the value.
 If successful, the return value is true, else, it is false. */
static bool tcDBInsert(TCADB *aDB, const char *kbuf, int ksiz, const char *vbuf, int vsiz){
  assert(aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
  bool vResult;
  
  if (vsiz > 4 && *vbuf == '{' && *(vbuf+vsiz-1) == '}') {
    vResult = tcADBReplace(aDB, kbuf, ksiz, vbuf, vsiz, tcadbputkeep);
  }
  else {
    vResult = tcadbputkeep(aDB, kbuf, ksiz, vbuf, vsiz);
  }
  return vResult;
}


/* Concatenate a value at the end of the existing record in a database object.
 `aDB' specifies the multiple database object.
 `kbuf' specifies the pointer to the region of the key.
 `ksiz' specifies the size of the region of the key.
 `vbuf' specifies the pointer to the region of the value.
 `vsiz' specifies the size of the region of the value.
 If successful, the return value is true, else, it is false. */
/*
 static bool tcMeDBputcat(TCADB *aDB, const void *kbuf, int ksiz, const void *vbuf, int vsiz){
 assert(aDB && kbuf && ksiz >= 0 && vbuf && vsiz >= 0);
 bool vResult;
 
 if (vsiz > 4 && *vbuf[0] == "{" && *vbuf[vsiz-1] == "}") {
 vResult = tcMeIndexReplace(aDB, kbuf, ksiz, vbuf, vsiz, tcadbputkeep);
 }
 else {
 vResult = tcadbputcat(aDB, kbuf, ksiz, vbuf, vsiz);
 }
 return vResult;
 }
 */

/* Remove a record of a multiple database object.
 `aDB' specifies the multiple database object.
 `kbuf' specifies the pointer to the region of the key.
 `ksiz' specifies the size of the region of the key.
 If successful, the return value is true, else, it is false. */
static bool tcDBDelete(TCADB *aDB, const char *kbuf, int ksiz){
  assert(aDB && kbuf && ksiz >= 0);
  
  return tcADBDelete(aDB, kbuf, ksiz);
}

/* Lock a method of the B+ tree database object.
 `bdb' specifies the B+ tree database object.
 `wr' specifies whether the lock is writer or not.
 If successful, the return value is true, else, it is false. */
static bool tcbdblockmethod(TCBDB *bdb, bool wr){
  assert(bdb);
  if(wr ? pthread_rwlock_wrlock(bdb->mmtx) != 0 : pthread_rwlock_rdlock(bdb->mmtx) != 0){
    tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    return false;
  }
  TCTESTYIELD();
  return true;
}


/* Unlock a method of the B+ tree database object.
 `bdb' specifies the B+ tree database object.
 If successful, the return value is true, else, it is false. */
static bool tcbdbunlockmethod(TCBDB *bdb){
  assert(bdb);
  if(pthread_rwlock_unlock(bdb->mmtx) != 0){
    tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    return false;
  }
  TCTESTYIELD();
  return true;
}


/* Lock the cache of the B+ tree database object.
 `bdb' specifies the B+ tree database object.
 If successful, the return value is true, else, it is false. */
static bool tcbdblockcache(TCBDB *bdb){
  assert(bdb);
  if(pthread_mutex_lock(bdb->cmtx) != 0){
    tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    return false;
  }
  TCTESTYIELD();
  return true;
}


/* Unlock the cache of the B+ tree database object.
 `bdb' specifies the B+ tree database object.
 If successful, the return value is true, else, it is false. */
static bool tcbdbunlockcache(TCBDB *bdb){
  assert(bdb);
  if(pthread_mutex_unlock(bdb->cmtx) != 0){
    tcbdbsetecode(bdb, TCETHREAD, __FILE__, __LINE__, __func__);
    return false;
  }
  TCTESTYIELD();
  return true;
}

/* Generate a unique ID number.
 `tdb' specifies the table database object.
 `inc' specifies the increment of the seed.
 The return value is the new unique ID number or -1 on failure. */
/*
 static int64_t tcbdbgenuidimpl(TCBDB *tdb, int64_t inc){
 assert(tdb);
 void *opq = tchdbopaque(tdb->hdb);
 uint64_t llnum, uid;
 if(inc < 0){
 uid = -inc - 1;
 } else {
 memcpy(&llnum, opq, sizeof(llnum));
 if(inc == 0) return TCITOHLL(llnum);
 uid = TCITOHLL(llnum) + inc;
 }
 llnum = TCITOHLL(uid);
 memcpy(opq, &llnum, sizeof(llnum));
 return uid;
 }
 */
/* Generate a unique ID number of a b+tree database object. */
/*
 int64_t tcbdbgenuid(TCBDB *tdb){
 assert(tdb);
 if(!BDBLOCKMETHOD(tdb, true)) return -1;
 if(!tdb->open || !tdb->wmode){
 tcbdbsetecode(tdb, TCEINVALID, __FILE__, __LINE__, __func__);
 BDBUNLOCKMETHOD(tdb);
 return -1;
 }
 int64_t rv = tcbdbgenuidimpl(tdb, 1);
 BDBUNLOCKMETHOD(tdb);
 return rv;
 }
 */

/* Call a versatile function for miscellaneous operations of a database object.
 `aDB' specifies the multiple database object.
 `name' specifies the name of the function.
 `args' specifies a list object containing arguments.
 If successful, the return value is a list object of the result.
 */
static TCLIST *tcDBExecCmd(TCADB *aDB, const char *name, const TCLIST *args){
  assert(aDB && name && args);
  int argc = TCLISTNUM(args);
#if defined(DEBUG)
  fprintf(stderr, "DBMisc(%s) argc=%d\n", name, argc);
  for(int i = 0; i < argc; i++){
    const char *vbuf;
    int vsiz;
    TCLISTVAL(vbuf, args, i, vsiz);
    fprintf(stderr, "  args[%d]: %s\n", i, vbuf);
  }
#endif
  TCLIST *rv;
  ADBSKEL *skel;
  switch(aDB->omode){
    case ADBOBDB:
      if(!strcmp(name, "put") || !strcmp(name, "putkeep") || !strcmp(name, "putcat") ||
         !strcmp(name, "putdup") || !strcmp(name, "putdupback")){
        if(argc > 1){
          rv = tclistnew2(1);
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          const char *vbuf;
          int vsiz;
          TCLISTVAL(vbuf, args, 1, vsiz);
          bool err = false;
          if (vsiz > 4 && *vbuf == '{' && *(vbuf+vsiz-1) == '}') {
            err = tcADBReplace(aDB, kbuf, ksiz, vbuf, vsiz, tcadbput);
            if(!strcmp(name, "put")){
              err = !tcBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbput);
            } else if(!strcmp(name, "putkeep")){
              err = !tcBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbputkeep);
            } else if(!strcmp(name, "putcat")){
              if(!tcbdbputcat(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putdup")){
              if(!tcbdbputdup(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putdupback")){
              if(!tcbdbputdupback(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            }
            /*else if(!strcmp(name, "putcat")){
             err = !tcBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbputcat);
             } else if(!strcmp(name, "putdup")){
             err = !tcBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbputdup);
             } else if(!strcmp(name, "putdupback")){
             err = !tcBDBIndexReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbputdupback);
             }*/
          }
          else {
            if(!strcmp(name, "put")){
              if(!tcbdbput(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putkeep")){
              if(!tcbdbputkeep(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putcat")){
              if(!tcbdbputcat(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putdup")){
              if(!tcbdbputdup(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            } else if(!strcmp(name, "putdupback")){
              if(!tcbdbputdupback(aDB->bdb, kbuf, ksiz, vbuf, vsiz)) err = true;
            }
          }
          
          if(err){
            tclistdel(rv);
            rv = NULL;
#if defined(DEBUG)
            fprintf(stderr, "BDBReplace Error %s.\n", kbuf); //err = true;
#endif
          }
        } else {
          rv = NULL;
        }
      } else if(!strcmp(name, "out")){
        if(argc > 0){
          rv = tclistnew2(1);
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          if(!tcBDBDelete(aDB->bdb, kbuf, ksiz, tcbdbout)){
            tclistdel(rv);
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!strcmp(name, "get")){
        if(argc > 0){
          rv = tclistnew2(1);
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          TCLIST *vals = tcbdbget4(aDB->bdb, kbuf, ksiz);
          if(vals){
            tclistdel(rv);
            rv = vals;
#if defined(DEBUG)
            fprintf(stderr, "DBMisc(%s) argc=%d\n", name, argc);
            for(int i = 0; i < TCLISTNUM(rv); i++){
              const char *vbuf;
              int vsiz;
              TCLISTVAL(vbuf, rv, i, vsiz);
              fprintf(stderr, "  value[%d]: %s\n", i, vbuf);
            }
#endif
          } else {
            tclistdel(rv);
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!strcmp(name, "putlist")){
        rv = tclistnew2(1);
        bool err = false;
        argc--;
        for(int i = 0; i < argc; i += 2){
          const char *kbuf, *vbuf;
          int ksiz, vsiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLISTVAL(vbuf, args, i + 1, vsiz);
          if(!tcBDBReplace(aDB->bdb, kbuf, ksiz, vbuf, vsiz, tcbdbputdup)){
            err = true;
            break;
          }
        }
        if(err){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "outlist")){
        rv = tclistnew2(1);
        bool err = false;
        for(int i = 0; i < argc; i++){
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          if(!tcBDBDelete(aDB->bdb, kbuf, ksiz, tcbdbout3) && tcbdbecode(aDB->bdb) != TCENOREC){ //todo: tcbdbout3 can delete duplication record.
            err = true;
            break;
          }
        }
        if(err){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "getlist")){
        rv = tclistnew2(argc * 2);
        bool err = false;
        for(int i = 0; i < argc; i++){
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLIST *vals = tcbdbget4(aDB->bdb, kbuf, ksiz);
          if(vals){
            int vnum = TCLISTNUM(vals);
            for(int j = 0; j < vnum; j++){
              TCLISTPUSH(rv, kbuf, ksiz);
              const char *vbuf;
              int vsiz;
              TCLISTVAL(vbuf, vals, j, vsiz);
              TCLISTPUSH(rv, vbuf, vsiz);
            }
            tclistdel(vals);
          } else if(tcbdbecode(aDB->bdb) != TCENOREC){
            err = true;
          }
        }
        if(err){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "getpart")){
        if(argc > 0){
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          int off = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
          if(off < 0) off = 0;
          if(off > INT_MAX / 2 - 1) off = INT_MAX - 1;
          int len = argc > 2 ? tcatoi(TCLISTVALPTR(args, 2)) : -1;
          if(len < 0 || len > INT_MAX / 2) len = INT_MAX / 2;
          int vsiz;
          char *vbuf = tcbdbget(aDB->bdb, kbuf, ksiz, &vsiz);
          if(vbuf){
            if(off < vsiz){
              rv = tclistnew2(1);
              vsiz -= off;
              if(vsiz > len) vsiz = len;
              if(off > 0) memmove(vbuf, vbuf + off, vsiz);
              tclistpushmalloc(rv, vbuf, vsiz);
            } else {
              rv = NULL;
              TCFREE(vbuf);
            }
          } else {
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!strcmp(name, "iterinit")){
        rv = tclistnew2(1);
        bool err = false;
        if(argc > 0){
          const char *kbuf;
          int ksiz;
          TCLISTVAL(kbuf, args, 0, ksiz);
          if(!tcbdbcurjump(aDB->cur, kbuf, ksiz)) err = true;
        } else {
          if(!tcbdbcurfirst(aDB->cur)) err = true;
        }
        if(err){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "iternext")){
        rv = tclistnew2(1);
        int ksiz;
        const char *kbuf = tcbdbcurkey3(aDB->cur, &ksiz);
        if(kbuf){
          TCLISTPUSH(rv, kbuf, ksiz);
          int vsiz;
          const char *vbuf = tcbdbcurval3(aDB->cur, &vsiz);
          if(vbuf) TCLISTPUSH(rv, vbuf, vsiz);
          tcbdbcurnext(aDB->cur);
        } else {
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "setindex")){
#if defined(DEBUG)
        //        fprintf(stderr, "%s\n", "setindex");
#endif
        rv = tclistnew2(1);
        bool err = false;
        argc--;
        for(int i = 0; i < argc; i += 2){
          const char *kbuf, *vbuf;
          int ksiz, vsiz;
          TCLISTVAL(kbuf, args, i, ksiz);
          TCLISTVAL(vbuf, args, i + 1, vsiz);
          int type = tctdbstrtoindextype(vbuf);
#if defined(DEBUG)
          //          fprintf(stderr, "index.key=%s\n", kbuf);
          //          fprintf(stderr, "index.opt='%s':%d\n", vbuf, type);
#endif
          if (type == TDBITVOID) {
            err = !tcBDBIndexRemove(aDB->bdb, kbuf, ksiz);
#if defined(DEBUG)
            if (err) {
              fprintf(stderr, "FieldName:%s; FieldOpt:%s Remove Index error! \n", kbuf, vbuf);
            }
#endif
          }else if (type == TDBITREINDEX) {
            err = !tcBDBReIndex(aDB->bdb, kbuf, ksiz, vbuf, vsiz, type);
          } else if(type >= 0){
            err = !tcBDBIndexSet(aDB->bdb, kbuf, ksiz, vbuf, vsiz, type);
#if defined(DEBUG)
            if (err) {
              fprintf(stderr, "FieldName:%s; FieldOpt:%s Set Index error! \n", kbuf, vbuf);
            }
#endif
          } else {
            err = true;
          }
        }
        if(err){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "sync")){
        rv = tclistnew2(1);
        if(!tcadbsync(aDB)){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "optimize")){
        rv = tclistnew2(1);
        const char *params = argc > 0 ? TCLISTVALPTR(args, 0) : NULL;
        if(!tcadboptimize(aDB, params)){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "vanish")){
        rv = tclistnew2(1);
        if(!tcadbvanish(aDB)){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "error")){
        rv = tclistnew2(1);
        int ecode = tcbdbecode(aDB->bdb);
        tclistprintf(rv, "%d: %s", ecode, tcbdberrmsg(ecode));
        uint8_t flags = tcbdbflags(aDB->bdb);
        if(flags & BDBFFATAL) tclistprintf(rv, "fatal");
      } else if(!strcmp(name, "defrag")){
        rv = tclistnew2(1);
        int64_t step = argc > 0 ? tcatoi(TCLISTVALPTR(args, 0)) : -1;
        if(!tcbdbdefrag(aDB->bdb, step)){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "cacheclear")){
        rv = tclistnew2(1);
        if(!tcbdbcacheclear(aDB->bdb)){
          tclistdel(rv);
          rv = NULL;
        }
      } else if(!strcmp(name, "regex")){
        if(argc > 0){
          const char *regex = TCLISTVALPTR(args, 0);
          int options = REG_EXTENDED | REG_NOSUB;
          if(*regex == '*'){
            options |= REG_ICASE;
            regex++;
          }
          regex_t rbuf;
          if(regcomp(&rbuf, regex, options) == 0){
            rv = tclistnew();
            int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
            if(max < 1) max = INT_MAX;
            BDBCUR *cur = tcbdbcurnew(aDB->bdb);
            tcbdbcurfirst(cur);
            TCXSTR *kxstr = tcxstrnew();
            TCXSTR *vxstr = tcxstrnew();
            while(max > 0 && tcbdbcurrec(cur, kxstr, vxstr)){
              const char *kbuf = TCXSTRPTR(kxstr);
              if(regexec(&rbuf, kbuf, 0, NULL, 0) == 0){
                TCLISTPUSH(rv, kbuf, TCXSTRSIZE(kxstr));
                TCLISTPUSH(rv, TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr));
                max--;
              }
              tcbdbcurnext(cur);
            }
            tcxstrdel(vxstr);
            tcxstrdel(kxstr);
            tcbdbcurdel(cur);
            regfree(&rbuf);
          } else {
            rv = NULL;
          }
        } else {
          rv = NULL;
        }
      } else if(!strcmp(name, "range")){
        rv = tclistnew();
        int bksiz = 0;
        const char *bkbuf = NULL;
        if(argc > 0) TCLISTVAL(bkbuf, args, 0, bksiz);
        int max = argc > 1 ? tcatoi(TCLISTVALPTR(args, 1)) : 0;
        if(max < 1) max = INT_MAX;
        int eksiz = 0;
        const char *ekbuf = NULL;
        if(argc > 2) TCLISTVAL(ekbuf, args, 2, eksiz);
        TCCMP cmp = tcbdbcmpfunc(aDB->bdb);
        void *cmpop = tcbdbcmpop(aDB->bdb);
        BDBCUR *cur = tcbdbcurnew(aDB->bdb);
        if(bkbuf){
          tcbdbcurjump(cur, bkbuf, bksiz);
        } else {
          tcbdbcurfirst(cur);
        }
        TCXSTR *kxstr = tcxstrnew();
        TCXSTR *vxstr = tcxstrnew();
        while(max > 0 && tcbdbcurrec(cur, kxstr, vxstr)){
          const char *kbuf = TCXSTRPTR(kxstr);
          int ksiz = TCXSTRSIZE(kxstr);
          if(ekbuf && cmp(kbuf, ksiz, ekbuf, eksiz, cmpop) >= 0) break;
          TCLISTPUSH(rv, kbuf, ksiz);
          TCLISTPUSH(rv, TCXSTRPTR(vxstr), TCXSTRSIZE(vxstr));
          max--;
          tcbdbcurnext(cur);
        }
        tcxstrdel(vxstr);
        tcxstrdel(kxstr);
        tcbdbcurdel(cur);
      } else if(!strcmp(name, "genuid")){
        rv = tclistnew2(1);
        //int nsiz = sprintf(numbuf, "%lld", (long long)tcbdbgenuid(aDB->bdb));
        char *vUUID = GenerateUID();
        tclistpush2(rv, vUUID);
        TCFREE(vUUID);
      } else {
        rv = NULL;
      }
      break;
    case ADBOSKEL:
      skel = aDB->skel;
      if(skel->misc){
        rv = skel->misc(skel->opq, name, args);
      } else {
        rv = NULL;
      }
      break;
    default:
      rv = NULL;
      break;
  }
  return rv;  
}

/* Store a record into a database object with a duplication handler.
 `mul' specifies the multiple database object.
 `kbuf' specifies the pointer to the region of the key.
 `ksiz' specifies the size of the region of the key.
 `vbuf' specifies the pointer to the region of the value.
 `vsiz' specifies the size of the region of the value.
 `proc' specifies the pointer to the callback function to process duplication.
 `op' specifies an arbitrary pointer to be given as a parameter of the callback function.
 If successful, the return value is true, else, it is false. */
/*
 static bool tcMeDBputproc(TMeDB *mul, const void *kbuf, int ksiz, const void *vbuf, int vsiz,
 TCPDPROC proc, void *op){
 assert(mul && kbuf && ksiz >= 0 && proc);
 if(!mul->adbs) return false;
 int idx = tcMeDBidx(mul, kbuf, ksiz);
 TCADB *adb = mul->adbs[idx];
 return tcadbputproc(adb, kbuf, ksiz, vbuf, vsiz, proc, op);
 }
 */

// END OF FILE
